#pragma once

#include<iostream>
#include<vector>
#include<semaphore.h>

template<class T>
class RingQueue
{
private:
    //申请信号量-- p()
    void p(sem_t& sem)
    {
        sem_wait(&sem);
    }

    //归还信号量++ v()
    void v(sem_t& sem)
    {
        sem_post(&sem);
    }

public:
    //默认构造
    RingQueue(int cap = 5)
        :_ring(cap)
        ,_cap(cap)
        ,_c_pos(0)
        ,_p_pos(0)
    {
        //信号量初始化
        sem_init(&_sem_data, 0, 0);
        sem_init(&_sem_room, 0, _cap);

        //锁初始化
        pthread_mutex_init(&_p_mutex, nullptr);
        pthread_mutex_init(&_c_mutex, nullptr);

    }

    // //生产者作业--单线程
    // void push(const T& data)
    // {
    //     p(_sem_room); //申请空间

    //     //生产过程
    //     _ring[_p_pos++] = data;
    //     _p_pos %= _cap;

    //     v(_sem_data); //归还数据
    // }

    // //消费者作业--单线程
    // void pop(T& data)
    // {
    //     p(_sem_data); //申请数据

    //     //消费过程
    //     data = _ring[_c_pos++];
    //     _c_pos %= _cap;

    //     v(_sem_room); //归还空间
    // }

    //生产者作业--多线程
    void push(const T& data)
    {
        p(_sem_room); //申请空间
        pthread_mutex_lock(&_p_mutex); //加锁

        //生产过程
        _ring[_p_pos++] = data;
        _p_pos %= _cap;

        pthread_mutex_unlock(&_p_mutex); //解锁
        v(_sem_data); //归还数据
    }

    //消费者作业--多线程
    void pop(T& data)
    {
        p(_sem_data); //申请数据
        pthread_mutex_lock(&_c_mutex); //加锁

        //消费过程
        data = _ring[_c_pos++];
        _c_pos %= _cap;

        pthread_mutex_unlock(&_c_mutex); //解锁
        v(_sem_room); //归还空间
    }

private:
    std::vector<T> _ring; //队列
    int _cap; //总容量
    sem_t _sem_data; //数据信号量
    sem_t _sem_room; //空间信号量
    int _c_pos; //消费者下标
    int _p_pos; //生产者下标
    //锁
    pthread_mutex_t _p_mutex;
    pthread_mutex_t _c_mutex;
};